/*
 * serial_communication.c
 *
 *  Created on: 18/08/2010
 *      Author: Oliv
 */

#include "typedef.h"
#include "serial_communication.h"
#include "usb_serial.h"
#include "led.h"

t_SerialFifo fifoReception;
t_SerialFifo fifoEmission;

BOOL newMsgReceived = FALSE;

/** power of ten used to read and write numbers to/from strings */
static U16 powTenFactors[5] ={1, 10, 100, 1000, 10000};

void readSerialData()
{
    U08 data;
    
    if (newMsgReceived == TRUE)
    {
        /* The last message has not been yet processed so we ignore the received character */
        return;
    }
    
    while(usb_serial_available())
    {
        data = usb_serial_getchar();
        
        switch (data)
        {
        case '$':
            /* Start character */
            fifoReception.u08WritePointer = 0;
            break;

        case '\n':
            /* End character */
            if (fifoReception.u08WritePointer && (fifoReception.u08Buffer[fifoReception.u08WritePointer - 1] == '\r'))
            {
                /* If the last charactere was '\r' then the end sequence (CRLF)  */
                /* has been detected and the whole message can be analyzed */
                newMsgReceived = TRUE;
                
            }
            break;

        default:
            /* For others charactercs, nothing is done here */
            break;
        }

        if (fifoReception.u08WritePointer < SERIAL_BUFFER_LENGTH)
        {
            /* Save the received byte in the reception buffer if it is not full */
            fifoReception.u08Buffer[fifoReception.u08WritePointer++] = data;
        }
		
		if(newMsgReceived)
		{
			/* Process the new received message */
	    	processNewMessage();
		}
    }



}

/**
 * Prepare and send an acknowledge message to inform the pc about the last request
 * \param[in] code : Code of the message on 3 bytes
 */
void SendAckMsg(U08* code)
{

    usb_serial_putchar('$');
    
    usb_serial_write(code, 3);
    
    usb_serial_write("\r\n", 2);

    /* Send the command */
    usb_serial_flush_output();
}

/**
 * Check if the current byte in the reception buffer is equal to the passed param
 * \param[in] byte : byte to compare
 *
 * \return The result of the comparison
 */
inline BOOL CheckByte(U08 byte)
{
    if(fifoReception.u08Buffer[fifoReception.u08ReadPointer] == byte)
    {
        fifoReception.u08ReadPointer++;
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

/**
 * Compare 2 string
 * \param[in] string : String to compare
 * \param[in] u08NbChar : Number of characters to compare
 *
 * \return
 *          TRUE: The 2 strings are identical
 *          FALSE: The 2 strings are different
 */
BOOL CheckString(const U08* string, U08 u08NbChar)
{
    BOOL retValue = TRUE;
    U08 i;

    for (i = 0; i < u08NbChar; i++)
    {
        if (fifoReception.u08Buffer[fifoReception.u08ReadPointer + i] != string[i])
        {
            retValue = FALSE;
            break;
        }

    }

    if (retValue == TRUE)
    {
        /* If the result is ok then move forward the pointer */
        fifoReception.u08ReadPointer += u08NbChar;
    }


    return retValue;
}

/** 
 * This function read a number from a string
 * \param[in] u08NbBytes : Number of bytes of the string to read
 * \param[out] result : Value read from the string
 *
 * \return
 *          TRUE: A value has been read
 *          FALSE: A value can't been read from the string
 */
BOOL ReadNumber(const U08 u08NbBytes, U16* result)
{
    U08 i;

    *result = 0;

    for (i = 0; i < u08NbBytes; i++)
    {
        /* verify that the byte is a numerical value */
        if ((fifoReception.u08Buffer[fifoReception.u08ReadPointer] >= '0') && (fifoReception.u08Buffer[fifoReception.u08ReadPointer] <= '9'))
        {
            *result += powTenFactors[u08NbBytes - 1 - i] * (fifoReception.u08Buffer[fifoReception.u08ReadPointer] - '0');
        }
        else
        {
            return FALSE;
        }

        fifoReception.u08ReadPointer++;
    }

    return TRUE;

}

void TestLedValue()
{
    U16 u16Index;
    U16 u16Value;
    
    if (!CheckByte(','))
    {
        SendAckMsg("ERR");
        return;
    }
    
    /* Read the led index */
    if (!ReadNumber(1, (U16*) & u16Index))
    {
        SendAckMsg("ERR");
        return;
    }
	usb_serial_write("1\r\n", 3);
    usb_serial_flush_output();

    if (!CheckByte(','))
    {
        SendAckMsg("ERR");
        return;
    }

	usb_serial_write("2\r\n", 3);
    usb_serial_flush_output();    

    /* Read the led value */
    if (!ReadNumber(1, (U16*) & u16Value))
    {
        SendAckMsg("ERR");
        return;
    }

	usb_serial_write("3\r\n", 3);
    usb_serial_flush_output();

	/* Check the message ending */
    if (!CheckString("\r\n", 2))
    {
        SendAckMsg("ERR");
        return;
    }

	usb_serial_write("4\r\n", 3);
    usb_serial_flush_output();
    
    /* Green Led */
    if (u16Index == 0)
    {
        if (u16Value == 0)
        {
            GREEN_LED_OFF();
        }
        else
        {
            GREEN_LED_ON();
        }
    }
    
    /* Red Run */
    else if (u16Index == 1)
    {
        if (u16Value == 0)
        {
            RED_LED_OFF();
        }
        else
        {
            RED_LED_ON();
        }
    }
    else
    {
        SendAckMsg("ERR");
        return;
    }

    SendAckMsg("TLV");
}

/**
 * Process a received message
 */
void processNewMessage()
{
	BOOL correctMsg = FALSE;
    /* Set the fifo reception Read pointer to the begining of the message */
    fifoReception.u08ReadPointer = 0;
	fifoReception.u08WritePointer = 0;

	newMsgReceived = FALSE;
	
    /* First test the start character */
    if (!CheckByte('$'))
    {
        SendAckMsg("ERR");
        return;
    }
    
    if(CheckByte('T'))
    {
        if(CheckByte('L'))
        {
            if(CheckByte('V'))
            {
                // TLV: Test Led Value
                TestLedValue();
				correctMsg = TRUE;
            }
        }
    }

	if(!correctMsg)
	{
		SendAckMsg("ERR");
        return;
	}
	
}
